#pragma once
#include<queue>

#define CSIZE 5

template<class T>
class BlockQueue
{
public:
    BlockQueue(int capacity = CSIZE)
        :_capacity(capacity)
    {
        pthread_mutex_init(&_mutex,nullptr);
        pthread_cond_init(&_c,nullptr);
        pthread_cond_init(&_p,nullptr);
    }

    bool IsFull()
    {
        return _q.size() == _capacity;
    }

    bool IsEmpty()
    {
        return _q.size() == 0;
    }
    void push(T& data)
    {
        pthread_mutex_lock(&_mutex);

        while(IsFull())
        {
            pthread_cond_wait(&_p,&_mutex);
        }

        _q.push(data);
        pthread_cond_signal(&_c);
        pthread_mutex_unlock(&_mutex);
    }

    void pop(T* ret)
    {
        pthread_mutex_lock(&_mutex);

        while(IsEmpty())
        {
            pthread_cond_wait(&_c,&_mutex);
        }

        *ret = _q.front();
        _q.pop();
        pthread_cond_signal(&_p);
        pthread_mutex_unlock(&_mutex);
    }


    ~BlockQueue()
    {
        pthread_mutex_destroy(&_mutex);
        pthread_cond_destroy(&_c);
        pthread_cond_destroy(&_p);
    }

private:
    queue<T> _q;
    int _capacity;
    pthread_mutex_t _mutex;
    pthread_cond_t _c;
    pthread_cond_t _p;
};

